package com.litbw.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.font.TextAttribute;
import java.util.Hashtable;
import java.util.Map;
import java.util.Observable;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import com.litbw.dbbackend.DBUserAdapter;
import com.litbw.publicobservable.BasicUIMessage;
import com.litbw.publicobservable.LoginMessage;
import com.litbw.publicobservable.LogoutMessage;
import com.litbw.user.User;

public class LoginPanel extends AbstractObservablePanel {

	// Strings
	private static final String REGISTER_STR = "Register";
	private static final String USERNAME_STR = "Email:";
	private static final String PASS_STR = "Password:";
	private static final String LOGIN_STR = "Login";
	private static final String LOGOUT_STR = "Logout";
	private static final String LOGIN_BRDR_STR = "Registered User Login";
	
	/** Number of columns to show in input boxes. */
	private static final int INPUT_CHARS = 10;
	
	/**
	 * Generated serial version UID.
	 */
	private static final long serialVersionUID = 4966340321141500794L;

	/**
	 * Minimum width of all panels in this class put together.
	 */
	private int min_width = 0;
	
	/**
	 * Maximum height that is required by this view.
	 */
	private int min_height = 0;
	
	/**
	 * The user text field. 
	 */
	private JTextField user;
	
	/**
	 * The password text field.
	 */
	private JTextField pass;
	
	/**
	 * The user/pass panel.
	 */
	private JPanel user_pass_panel;
	
	/**
	 * The logout panel.
	 */
	private JPanel logout_panel;
	
	/**
	 * The register panel.
	 */
	private JPanel label_panel;
	
	/**
	 * Create a new LoginPanel.
	 */
	public LoginPanel() {
		super(new BorderLayout());
		
		// Setup all the inner panels.
		setupRegisterPanel();
		setupLoginPanel();
		setupLogoutPanel();
		
		setMinimumSize(new Dimension(min_width, min_height));
		setPreferredSize(new Dimension(min_width, min_height));
		
		// Switch to login view.
		setLoginView(true);
		
	}
	
	private void setupLogoutPanel() {
		
		logout_panel = new JPanel(new GridBagLayout());
		final GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = GridBagConstraints.CENTER;
		gbc.gridy = GridBagConstraints.CENTER;
		
		// Just create a JLabel with blue underlined text that is clickable.
		final JLabel logout_lbl = new JLabel(LOGOUT_STR,
											   SwingConstants.CENTER);
		
		
		// Setup AttributeSet for rendering font.
		final Map<TextAttribute, Object> attrs = 
				new Hashtable<TextAttribute, Object>();
		attrs.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
		attrs.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
		attrs.put(TextAttribute.SIZE, 14);
		attrs.put(TextAttribute.FAMILY, Font.SANS_SERIF);
		attrs.put(TextAttribute.FOREGROUND, Color.BLUE );
		
		logout_lbl.setFont(new Font(attrs));
		
		// Setup a mouse listener to signal to ui on click.
		logout_lbl.addMouseListener(new MouseListener() {

			@Override
			public void mouseClicked(MouseEvent arg0) {}

			@Override
			public void mouseEntered(MouseEvent e) {}

			@Override
			public void mouseExited(MouseEvent e) {}

			@Override
			public void mousePressed(MouseEvent e) {}

			@Override
			public void mouseReleased(MouseEvent e) {
				logout();
			}
			
		});
		
		// Add to center so the label will NOT be at the absolute right side.
		logout_panel.add(logout_lbl, gbc);
		
	}
	
	/**
	 * Setup the Register Link panel.
	 */
	private void setupRegisterPanel() {
		
		label_panel = new JPanel(new GridBagLayout());
		final GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = GridBagConstraints.CENTER;
		gbc.gridy = GridBagConstraints.CENTER;
		
		// Just create a JLabel with blue underlined text that is clickable.
		final JLabel register_lbl = new JLabel(REGISTER_STR,
											   SwingConstants.CENTER);
		
		
		// Setup AttributeSet for rendering font.
		final Map<TextAttribute, Object> attrs = 
				new Hashtable<TextAttribute, Object>();
		attrs.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
		attrs.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
		attrs.put(TextAttribute.SIZE, 14);
		attrs.put(TextAttribute.FAMILY, Font.SANS_SERIF);
		attrs.put(TextAttribute.FOREGROUND, Color.BLUE );
		
		register_lbl.setFont(new Font(attrs));
		
		// Setup a mouse listener to signal to ui on click.
		register_lbl.addMouseListener(new MouseListener() {

			@Override
			public void mouseClicked(MouseEvent arg0) {}

			@Override
			public void mouseEntered(MouseEvent e) {}

			@Override
			public void mouseExited(MouseEvent e) {}

			@Override
			public void mousePressed(MouseEvent e) {}

			@Override
			public void mouseReleased(MouseEvent e) {
				register();
			}
			
		});
		
		// Add to center so the label will NOT be at the absolute left side.
		label_panel.add(register_lbl, gbc);
		
		// Update the minimum size and overall LoginPanel min_width/min_height.
		label_panel.setMinimumSize(label_panel.getPreferredSize());
		min_width += label_panel.getPreferredSize().getWidth() + label_panel.getInsets().left + label_panel.getInsets().right;
		min_height = (int)Math.max(label_panel.getPreferredSize().getHeight(), min_height);
		
	}
	
	/**
	 * Setup the login panel.
	 */
	private void setupLoginPanel() {
		
		// New panel to hold them in the right spot.
		user_pass_panel = new JPanel();
		user_pass_panel.setBorder(
				BorderFactory.createTitledBorder(LOGIN_BRDR_STR));
		
		// Create all the components we will need.
		user = new JTextField(INPUT_CHARS);
		pass = new JPasswordField(INPUT_CHARS);

		
		final JLabel user_lbl = new JLabel(USERNAME_STR);
		final JLabel pass_lbl = new JLabel(PASS_STR);
		
		final JButton submit_btn = new JButton(LOGIN_STR);
		submit_btn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				
				login();
				
				// Clear the user/pass fields.
				user.setText("");
				pass.setText("");
				
			} });
		
		user_pass_panel.add(user_lbl);
		user_pass_panel.add(user);
		user_pass_panel.add(pass_lbl);
		user_pass_panel.add(pass);
		user_pass_panel.add(submit_btn);
				
		// Update the minimum size and overall LoginPanel min_width/min_height.
		user_pass_panel.setMinimumSize(user_pass_panel.getPreferredSize());
		min_width += user_pass_panel.getPreferredSize().getWidth() + user_pass_panel.getInsets().left + user_pass_panel.getInsets().right;
		min_height = (int)Math.max(user_pass_panel.getPreferredSize().getHeight(), min_height);
		
	}
	
	/**
	 * Execute login operation including field checking.
	 */
	private void login() {
		
		// Check to make sure the fields are not empty.
		if (user.getText().isEmpty() || pass.getText().isEmpty()) {
			JOptionPane.showMessageDialog(this, "Username and Password are required!", "Login Error", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		// Do login 
		final User usr = DBUserAdapter.getUserFromUsernameAndPass(user.getText().trim(),
				pass.getText(), true);
		
		// If the usr does not exist
		if (usr == null) {
			JOptionPane.showMessageDialog(this, "Did not recognize username and/or password.", "Login Failed", JOptionPane.INFORMATION_MESSAGE);
		} else {
			// The user has been verified and User object created so send the LoginMessage
			setChanged();
			notifyObservers(new LoginMessage(usr));
						
			// Change the view to logout view.
			setLoginView(false);
			
		}

	}
	
	/**
	 * Switch from login mode to logout mode.
	 * @param flag True if in login mode.
	 */
	private void setLoginView(final boolean flag) {
		
		if (!flag) {
			
			remove(user_pass_panel);
			remove(label_panel);
			add(logout_panel, BorderLayout.CENTER);
			
		} else {
			
			remove(logout_panel);
			add(user_pass_panel, BorderLayout.EAST);
			add(label_panel, BorderLayout.CENTER);
			
		}
		
		this.updateUI();
		
	}
	
	/**
	 * Logout.
	 */
	private void logout() {
		
		// Send the logout message regardless.
		setChanged();
		notifyObservers(new LogoutMessage());
		
		// Switch to the login/register view.
		setLoginView(true);
	}
	
	/**
	 * Execute register operation. (Call the UI to show register).
	 */
	private void register() {
		// Signal the UI to switch to the register screen.
		setChanged();
		notifyObservers(new BasicUIMessage(BasicUIMessage.UISignal.SHOW_REGISTER));
		
	}
	
	@Override
	public void update(final Observable obs, final Object arg) {
		System.out.println("LoginPanel recieved message!");
		if (arg instanceof LoginMessage) {
			setLoginView(false);
		} else if (arg instanceof LogoutMessage) {
			setLoginView(true);
		}	
	}
}
